#pragma once
#include "Includes.h"

namespace SD_Tools
{
	const double SD_PI = 3.14159265358979323846;
	const float SD_PI_F = (float) SD_PI;
	class Vector2;
	class Vector;
	class Angle;
	class Rectangle2;

	template<typename T> inline T* MakePointerGEN( PVOID thisptr, int offset ) { return reinterpret_cast<T*>( reinterpret_cast<UINT_PTR>( thisptr ) + offset ); }

	DWORD GetRealDir( HINSTANCE hInstance, wchar_t* Buffer, int MaxSize /*= 512*/ );

	namespace MathHelper
	{
		template<typename T> T GetDiff(T a, T b);
		template<typename T> T GetMax(T a, T b);
		template<typename T> T GetMin(T a, T b);
		template<typename T> bool IsNear(T a, T b, T Range);
		template<typename T> T ToRange(T a, T Left, T Right);
		template<typename T> T FixRange(T a, T Left, T Right);
		template<typename T> T GetRange(T a, T b, T Left, T Right);
		template<typename T> T GetRangeSigned(T a, T b, T Left, T Right);
		template<typename T> bool IsInRange(T a, T b, T Left, T Right, T Range);
		double RadToDeg(double Alpha);
		double DegToRad(double Alpha);
		float RadToDegf(float Alpha);
		float DegToRadf(float Alpha);

	} // End of Namespace MathHelper

	class Vector2
	{
	private:
	public:
		union
		{
			struct
			{
				float x;
				float y;
			};
			float RawData[2];
		};
	private:
	public:
		Vector2() {};
		Vector2(float x, float y): x(x), y(y) {};
		Vector2(int x, int y): x((float) x), y((float) y) {};
		void Clear();
		float Magnitude();
		float MagnitudeSqr();
		void Subtract(Vector2& Vec);
		void Add(Vector2& Vec);
		void Multiply(float Mul);
		void Turn(float Angle);
		void Turn(float Angle, Vector2& Origin);
	};

	class Vector
	{
	private:
	public:
		union
		{
			struct
			{
				float x;
				float y;
				float z;
			};
			float RawData[3];
		};
	private:
	public:
		Vector() {};
		Vector(float x, float y, float z): x(x), y(y), z(z) {};
		Vector(int x, int y, int z): x((float) x), y((float) y), z((float) z) {};
		void Clear();
		float Magnitude();
		float MagnitudeSqr();
		void Subtract(Vector& Vec);
		void Add(Vector& Vec);
		void Multiply(float Mul);
		void CrossProduct(Vector& Vec);
		float DotProduct(Vector& Vec);
		void ToAngles(Angle* Ang);
		void Normalize();
	};

	class Vector4
	{
	private:
	public:
		union
		{
			struct
			{
				float x;
				float y;
				float z;
				float w;
			};
			float RawData[4];
		};
	private:
	public:
		Vector4() {};
		Vector4(float x, float y, float z, float w): x(x), y(y), z(z), w(w) {};
		Vector4(int x, int y, int z, int w): x((float) x), y((float) y), z((float) z), w((float)w) {};
	};

	class Angle
	{
	private:
	public:
		union
		{
			struct
			{
				float Pitch;
				float Yaw;
				float Roll;
			};
			struct
			{
				float x;
				float y;
				float z;
			};
			float RawData[3];
		};
	private:
	public:
		Angle() {};
		Angle(float Pitch, float Yaw, float Roll): Pitch(Pitch), Yaw(Yaw), Roll(Roll) {};
		Angle(int Pitch, int Yaw, int Roll): Pitch((float) Pitch), Yaw((float) Yaw), Roll((float) Roll) {};
		void Clear();
		void Add(Angle& Ang);
		void Subtract(Angle& Ang);
		void Multiply(float Multiplier);
		void ToVectors(Vector* Forward, Vector* Right, Vector* Up);
		void ToVectors_s(Vector* Forward, Vector* Right, Vector* Up);
	};
	
	//////////////////////////////////////////////////////////////////////////
	namespace MathHelper
	{
		Vector AddVector(Vector& Vec1, Vector& Vec2);
		Vector SubVector(Vector& Vec1, Vector& Vec2);
		Vector MulVector(Vector& Vec, float Mul);
		Vector CrossVector(Vector& Vec1, Vector& Vec2);
		float DotVector(Vector& Vec1, Vector& Vec2);
		void ClearVector(Vector* Vec);
		float MagnitudeVector(Vector& Vec);
		float MagnitudeSqrVector(Vector& Vec);
		float DistanceVector(Vector& Vec1, Vector& Vec2);
		float DistanceSqrVector(Vector& Vec1, Vector& Vec2);
		Angle AddAngle(Angle& Ang1, Angle& Ang2);
		Angle SubAngle(Angle& Ang1, Angle& Ang2);
		Angle MulAngle(Angle& Ang, float Mul);
		void ClearAngle(Angle* Ang);
		void AngleToVectors(Angle& Angle, Vector* Forward, Vector* Right, Vector* Up);
		void AngleToVectors_s(Angle& Angle, Vector* Forward, Vector* Right, Vector* Up);
		void VectorToAngle(Vector& Vector, Angle* Out);
		
		//************************************
		// Method:    GetDiff
		// Profit:	  Gets the Difference between a and b, the operators >, < and - should be implemented
		// FullName:  SD_Tools::MathHelper<T>::GetDiff
		// Returns:   T
		// Notes:
		// -"return ((a>b) ? (a-b) : (b-a));"
		//************************************
		template<typename T> T GetDiff( T a, T b )
		{
			return ((a>b) ? (a-b) : (b-a));
		}

		//************************************
		// Method:    GetMax
		// Profit:	  Gets the greater one
		// FullName:  SD_Tools::MathHelper<T>::GetMax
		// Returns:   T
		// Notes:
		// -"return (a>b) ? a : b;"
		//************************************
		template<typename T> T GetMax( T a, T b )
		{
			return (a>b) ? a : b;
		}

		//************************************
		// Method:    GetMin
		// Profit:	  Gets the smaller one
		// FullName:  SD_Tools::MathHelper<T>::GetMin
		// Returns:   T
		// Notes:
		// -"return (a>b) ? b : a;"
		//************************************
		template<typename T> T GetMin( T a, T b )
		{
			return (a>b) ? b : a;
		}

		//************************************
		// Method:    IsNear
		// Profit:	  returns true if a is in <Range> of b
		// FullName:  SD_Tools::MathHelper<T>::IsNear
		// Returns:   bool
		// Notes:
		// -"return (b-Range < a && b+Range > a);"
		//************************************
		template<typename T> bool IsNear( T a, T b, T Range )
		{
			return (b-Range < a && b+Range > a);
		}

		//************************************
		// Method:    ToRange
		// Profit:	  Converts a in the left - right interval
		// FullName:  SD_Tools::MathHelper<T>::ToRange
		// Returns:   T
		// Notes:
		// -None
		//************************************
		template<typename T> T ToRange( T a, T Left, T Right )
		{
			while ((a < Left) || (a > Right))
			{
				if (a < Left)
				{
					a += Right - Left;
				}
				else if (a > Right)
				{
					a -= Right - Left;
				}
			}
			return a;
		}

		//************************************
		// Method:    FixRange
		// Profit:	  Fixes a in the left - right interval
		// FullName:  SD_Tools::MathHelper<T>::FixRange
		// Returns:   T
		// Notes:
		// -None
		//************************************
		template<typename T> T FixRange( T a, T Left, T Right )
		{
			if (a < Left)
			{
				a = Left;
			}
			else if (a > Right)
			{
				a = Right;
			}
			return a;
		}

		//************************************
		// Method:    GetRange
		// Profit:	  returns the difference of a and b in a circle interval from left to right
		// FullName:  SD_Tools::MathHelper<T>::GetRange
		// Returns:   T
		// Notes:
		// -None
		//************************************
		template<typename T> T GetRange( T a, T b, T Left, T Right )
		{
			T Rslt;
			T TotalRange = Right-Left;
			if (a < b)
			{
				Rslt = a;
				a = b;
				b = Rslt;
			}
			Rslt = a - b;
			if (Rslt > TotalRange/2)
			{
				Rslt -= TotalRange;
			}
			if (Rslt < 0)
			{
				Rslt *= -1;
			}
			return Rslt;
		}

		//************************************
		// Method:    GetRangeSigned
		// Profit:	  returns the signed difference of a and b in a circle interval from left to right
		// FullName:  SD_Tools::MathHelper<T>::GetRangeSigned
		// Returns:   T
		// Notes:
		// -None
		//************************************
		template<typename T> T GetRangeSigned( T a, T b, T Left, T Right )
		{
			T Rslt;
			T TotalRange = Right-Left;
			if (a < b)
			{
				Rslt = a;
				a = b;
				b = Rslt;
			}
			Rslt = a - b;
			if (Rslt > TotalRange/2)
			{
				Rslt -= TotalRange;
			}
			return Rslt;
		}

		//************************************
		// Method:    IsInRange
		// Profit:	  Returns true if a is in the <Range> of b in the circle interval left-right
		// FullName:  SD_Tools::MathHelper<T>::IsInRange
		// Returns:   bool
		// Notes:
		// -None
		//************************************
		template<typename T> bool IsInRange( T a, T b, T Left, T Right, T Range )
		{
			T temp;
			temp = GetRange(a,b,Left,Right);
			if (temp <= Range)
			{
				return true;
			}
			return false;
		}

	} // End of Namespace MathHelper
}